package com.urbane.dto.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;

/**
 * 统一 API 响应封装类
 *
 * <p> 用于规范所有 Controller 接口的返回格式，确保前后端数据交互的一致性。
 * 遵循 Restful 设计原则，包含状态码、提示信息和业务数据。</p>
 *
 * <p> 使用泛型 <T> 支持返回任意类型的业务数据，提高代码复用性和类型安全性。</p>
 *
 * @param <T> 业务数据的类型
 * @author 龙茶清欢
 * @version 1.0
 * @since 2025/7/23 10:05
 */
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL) // 全局忽略 null 值字段, 即 null 值字段不会被序列化
public class ApiResponse<T> {

    /**
     * 状态码
     *
     * <p> 使用HTTP状态码语义，便于前端统一处理：</p>
     * <ul>
     *   <li> 200: 请求成功 </li>
     *   <li> 400: 客户端请求错误 </li>
     *   <li> 401: 未授权 </li>
     *   <li> 403: 禁止访问 </li>
     *   <li> 404: 资源不存在 </li>
     *   <li> 500: 服务器内部错误 </li>
     * </ul>
     *
     * <p> 也可根据业务需求定义自定义状态码，但建议在文档中明确说明。</p>
     */
    private int code;

    /**
     * 响应消息
     *
     * <p> 给用户或开发者的提示信息，应该简洁明了：</p>
     * <ul>
     *   <li> 成功时: "success", "操作成功"等 </li>
     *   <li> 失败时: 具体的错误描述，如"用户名不能为空" </li>
     * </ul>
     *
     * <p> 对于生产环境，错误消息应该友好，避免暴露敏感系统信息。</p>
     */
    private String message;

    /**
     * 响应数据
     *
     * <p>业务接口返回的具体数据内容：</p>
     * <ul>
     *   <li>查询接口: 返回查询结果对象或列表</li>
     *   <li>新增/修改接口: 返回创建/修改后的对象</li>
     *   <li>删除接口: 可返回null或操作结果标识</li>
     * </ul>
     *
     * <p>注意：当请求失败时，此字段为null，Jackson序列化时会自动忽略该字段。</p>
     */
    private T data;

    /**
     * 时间戳
     *
     * <p>返回当前时间，用于服务端响应时间计算。</p>
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime timestamp; // 时间戳

    /**
     * 全参构造方法
     *
     * @param code 状态码
     * @param message 响应消息
     * @param data 业务数据
     */
    private ApiResponse(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.timestamp = LocalDateTime.now();
    }

    // ==================== 静态工厂方法 ====================
    // 推荐使用静态工厂方法，提供更优雅的对象创建方式

    /**
     * 创建成功响应（无数据）
     *
     * <p>适用于删除、更新等不需要返回数据的操作。</p>
     *
     * @param <T> 业务数据类型
     * @return 成功地响应对象
     */
    public static <T> ApiResponse<T> success() {
        return new ApiResponse<>(HttpStatus.SUCCESS.code, HttpStatus.SUCCESS.message, null);
    }

    /**
     * 创建成功响应（带数据）
     *
     * @param <T> 业务数据类型
     * @param data 要返回的业务数据
     * @return 成功地响应对象
     */
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(HttpStatus.SUCCESS.code, HttpStatus.SUCCESS.message, data);
    }

    /**
     * 创建错误响应
     *
     * @param <T> 业务数据类型
     * @param code 错误状态码
     * @param message 错误描述信息
     * @return 错误的响应对象（data字段为null）
     */
    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message, null);
    }

    /**
     * 创建客户端错误响应（400 状态码）
     *
     * <p>适用于参数校验失败、业务逻辑错误等客户端问题。</p>
     *
     * @param <T> 业务数据类型
     * @return 客户端错误的响应对象
     */
    public static <T> ApiResponse<T> badRequest() {
        return error(HttpStatus.BAD_REQUEST.code, HttpStatus.BAD_REQUEST.message);
    }

    /**
     * 创建未授权错误响应（401 状态码）
     *
     * @param <T> 业务数据类型
     * @return 未授权的响应对象
     */
    public static <T> ApiResponse<T> unauthorized() {
        return error(HttpStatus.UNAUTHORIZED.code, HttpStatus.UNAUTHORIZED.message);
    }

    /**
     * 创建禁止访问错误响应（403 状态码）
     *
     * @param <T> 业务数据类型
     * @return 禁止访问的响应对象
     */
    public static <T> ApiResponse<T> forbidden() {
        return error(HttpStatus.FORBIDDEN.code, HttpStatus.FORBIDDEN.message);
    }

    /**
     * 创建资源不存在错误响应（404 状态码）
     *
     * @param <T> 业务数据类型
     * @return 资源不存在的响应对象
     */
    public static <T> ApiResponse<T> notFound() {
        return error(HttpStatus.NOT_FOUND.code, HttpStatus.NOT_FOUND.message);
    }

    /**
     * 创建服务器内部错误响应（500 状态码）
     *
     * @param <T> 业务数据类型
     * @return 服务器内部错误的响应对象
     */
    public static <T> ApiResponse<T> serverError() {
        return error(HttpStatus.INTERNAL_SERVER_ERROR.code, HttpStatus.INTERNAL_SERVER_ERROR.message);
    }

    /**
     * 创建失败响应（自定义状态码和消息）
     *
     * @param <T> 业务数据类型
     * @param code 错误状态码
     * @param message 错误描述信息
     * @return 错误的响应对象
     */
    public static <T> ApiResponse<T> fail(int code, String message) {
        return error(code, message);
    }

    /**
     * HTTP 状态码枚举类，参考 Spring 提供的 HttpStatus 枚举类。
     *
     * <p>定义HTTP状态码常量，并包含相应的描述信息。</p>
     * <p>使用枚举类，可避免错误状态码输入，并统一错误描述信息。</p>
     */
    @Getter
    @RequiredArgsConstructor
    public enum HttpStatus {
        SUCCESS(200, "操作成功"),
        BAD_REQUEST(400, "参数验证失败"),
        UNAUTHORIZED(401, "未授权"),
        FORBIDDEN(403, "禁止访问"),
        NOT_FOUND(404, "未找到"),
        INTERNAL_SERVER_ERROR(500, "服务器内部错误"),
        ;

        /**
         * 状态码
         */
        private final int code;

        /**
         * 描述信息
         */
        private final String message;
    }
}
